import 'dart:convert';
import 'dart:ui' as ui;

import 'package:douhuaxiangsu/entity/palette_model.dart';
import 'package:flutter/material.dart';

import '../utils/constants_utils.dart';
import '../utils/common_utils.dart';
import 'canvas_step_type.dart';
import 'canvas_type.dart';

/// 作品实体
class ArtworkModel {
  int? id;

  ///  版本号
  String version;

  ///  图片
  String? image64;

  ///  画布数据
  CanvasModel canvas;

  /// 调色盘
  PaletteModel palette;

  ArtworkModel({
    required this.id,
    required this.version,
    required this.image64,
    required this.canvas,
    required this.palette,
  });

  ArtworkModel.fromJson(Map<String, dynamic> json)
    : id = json['id'] ?? 0,
      version = json['version'] ?? ConstantsUtils.version,
      image64 = json['image64'],
      canvas = CanvasModel.fromJson(json['canvas'] ?? {}),
      palette = PaletteModel.fromJson(json['palette'] ?? {});

  /// 注意,此处转JSON时不会将id导出
  Map<String, dynamic> toJson() => {
    'version': version,
    'image64': image64,
    'canvas': canvas.toJson(),
    'palette': palette.toJson(),
  };
}

///  画布数据
class CanvasModel {
  /// 画布类型
  CanvasType type;

  /// 画布大小
  SizeModel size;

  /// 点位数据
  Map<double, Map<double, Color>> pointData;

  /// 当前步骤idx
  int stepIdx;

  /// 操作历史
  List<StepModel> step;

  CanvasConfig canvasConfig;

  CanvasModel({
    required this.type,
    required this.size,
    required this.pointData,
    required this.stepIdx,
    required this.step,
    required this.canvasConfig,
  });

  CanvasModel.fromJson(Map<String, dynamic> json)
    : type = CanvasType.values[json['type'] ?? 0],
      size = SizeModel.fromJson(json['size'] ?? {}),
      pointData =
          (json['pointData'] as List?)
              ?.map((e) => PointDataModel.fromJson(e))
              .fold<Map<double, Map<double, Color>>>({}, (map, point) {
                if (!map.containsKey(point.x.toDouble())) {
                  map[point.x.toDouble()] = {};
                }
                map[point.x.toDouble()]![point.y.toDouble()] = point.color;
                return map;
              }) ??
          {},
      stepIdx = json['stepIdx'] ?? -999,
      step =
          (json['step'] as List<dynamic>?)
              ?.map((e) => StepModel.fromJson(e as Map<String, dynamic>))
              .toList() ??
          [],
      canvasConfig = CanvasConfig.fromJson(json['canvasConfig'] ?? {});

  Map<String, dynamic> toJson() => {
    'type': type.index,
    'size': size.toJson(),
    'pointData': pointData.entries
        .expand(
          (xEntry) => xEntry.value.entries.map(
            (yEntry) => PointDataModel(
              x: xEntry.key,
              y: yEntry.key,
              color: yEntry.value,
            ).toJson(),
          ),
        )
        .toList(),
    'stepIdx': stepIdx,
    'step': step.map((e) => e.toJson()).toList(),
    'canvasConfig': canvasConfig.toJson(),
  };
}

/// 画布大小
class SizeModel {
  int x;
  int y;

  SizeModel({required this.x, required this.y});

  SizeModel.fromJson(Map<String, dynamic> json)
    : x = json['x'] ?? 32,
      y = json['y'] ?? 32;

  Map<String, dynamic> toJson() => {'x': x, 'y': y};
}

/// 画布配置
class CanvasConfig {
  /// 是否显示坐标
  bool showPosition;

  /// 是否显示网格
  bool showGrid;

  /// 像素点样式
  PointStyleModel pointStyle;

  CanvasConfig({
    required this.showPosition,
    required this.showGrid,
    required this.pointStyle,
  });

  CanvasConfig.fromJson(Map<String, dynamic> json)
    : showPosition = json['showPosition'] ?? false,
      showGrid = json['showGrid'] ?? true,
      pointStyle = PointStyleModel.fromJson(
        json['pointStyle'] as Map<String, dynamic>? ?? {},
      );

  Map<String, dynamic> toJson() => {
    'showPosition': showPosition,
    'showGrid': showGrid,
    'pointStyle': pointStyle.toJson(),
  };
}

/// 像素点样式
class PointStyleModel {
  /// 类型 default 或 custom
  String type;

  /// default时是样式的下标,custom时是图片的base64
  String data;

  /// 图片缓存
  Map<String, ui.Image> imageCacheMap = {};

  PointStyleModel({required this.type, required this.data});

  PointStyleModel.fromJson(Map<String, dynamic> json)
    : type = json['type'] ?? 'default',
      data = json['data'] ?? '1';

  Map<String, dynamic> toJson() => {'type': type, 'data': data};

  String getStyleText() {
    if (type == 'default') {
      switch (data) {
        case '1':
          return '正方形';
        case '2':
          return '圆形';
        case '3':
          return '圆环';
        case '4':
          return '十字';
        default:
          return '正方形';
      }
    } else {
      return '自定义';
    }
  }

  Widget getStyleWidget() {
    if (type == 'default') {
      switch (data) {
        case '1':
          return Icon(Icons.square);
        case '2':
          return Icon(Icons.circle);
        case '3':
          return Icon(Icons.trip_origin);
        case '4':
          return Icon(Icons.close);
        default:
          return Icon(Icons.square);
      }
    } else {
      Widget trailing;
      try {
        trailing = Image.memory(base64Decode(data));
      } catch (e) {
        trailing = Icon(Icons.error);
      }
      return trailing;
    }
  }
}

/// 点位数据
class PointDataModel {
  double x;
  double y;
  Color color;

  PointDataModel({required this.x, required this.y, required this.color});

  PointDataModel.fromJson(Map<String, dynamic> json)
    : x = json['x'] as double,
      y = json['y'] as double,
      color = CommonUtils.hex2Color(json['color'] as String);

  Map<String, dynamic> toJson() => {
    'x': x,
    'y': y,
    'color': CommonUtils.color2Hex(color),
  };
}

/// 操作历史
class StepModel {
  /// 操作类型
  CanvasStepType operate;

  /// 本次操作执行的修改
  String jsonExecute;

  /// 回退时需要做的修改
  String jsonUndo;

  /// 本次操作执行的修改
  Map<double, Map<double, Color>> execute;

  /// 回退时需要做的修改
  Map<double, Map<double, Color>> undo;

  StepModel({
    required this.operate,
    required this.jsonExecute,
    required this.jsonUndo,
    required this.execute,
    required this.undo,
  });

  StepModel.fromJson(Map<String, dynamic> json)
    : operate = CanvasStepType.values[json['operate'] ?? 0],
      jsonExecute = json['json_execute'] ?? '',
      jsonUndo = json['json_undo'] ?? '',
      execute =
          (json['execute'] as List?)
              ?.map((e) => PointDataModel.fromJson(e))
              .fold<Map<double, Map<double, Color>>>({}, (map, point) {
                if (!map.containsKey(point.x.toDouble())) {
                  map[point.x.toDouble()] = {};
                }
                map[point.x.toDouble()]![point.y.toDouble()] = point.color;
                return map;
              }) ??
          {},
      undo =
          (json['undo'] as List?)
              ?.map((e) => PointDataModel.fromJson(e))
              .fold<Map<double, Map<double, Color>>>({}, (map, point) {
                if (!map.containsKey(point.x.toDouble())) {
                  map[point.x.toDouble()] = {};
                }
                map[point.x.toDouble()]![point.y.toDouble()] = point.color;
                return map;
              }) ??
          {};

  Map<String, dynamic> toJson() => {
    'operate': operate.index,
    'json_execute': jsonExecute,
    'json_undo': jsonUndo,
    'execute': execute.entries
        .expand(
          (xEntry) => xEntry.value.entries.map(
            (yEntry) => PointDataModel(
              x: xEntry.key,
              y: yEntry.key,
              color: yEntry.value,
            ).toJson(),
          ),
        )
        .toList(),
    'undo': undo.entries
        .expand(
          (xEntry) => xEntry.value.entries.map(
            (yEntry) => PointDataModel(
              x: xEntry.key,
              y: yEntry.key,
              color: yEntry.value,
            ).toJson(),
          ),
        )
        .toList(),
  };
}
